/*
 * Copyright (c) 2006-2022, RT-Thread Development Team
 * Copyright (c) 2022, Xiaohua Semiconductor Co., Ltd.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-04-28     CDT          first version
 */

#include "board.h"

#ifdef BSP_USING_SPI
#include "drv_spi.h"
#endif

#if defined(RT_USING_FAL)
#include <fal.h>
#endif

/* unlock/lock peripheral */
#define EXAMPLE_PERIPH_WE               (LL_PERIPH_GPIO | LL_PERIPH_EFM | LL_PERIPH_FCG | \
                                         LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_SRAM)
#define EXAMPLE_PERIPH_WP               (LL_PERIPH_EFM | LL_PERIPH_FCG | LL_PERIPH_SRAM)

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None
  * @retval None
  */
void Error_Handler(void)
{
    /* USER CODE BEGIN Error_Handler */
    /* User can add his own implementation to report the HAL error return state */
    while (1)
    {
    }
    /* USER CODE END Error_Handler */
}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{
    // 防止bootloader更改BASEPRI的值，造成rtthread调度器无法正常工作
    // BASEPRI 设置为n后，屏蔽所有优先级数值大于等于n的中断和异常
    __set_BASEPRI(0);

    stc_clock_xtal_init_t stcXtalInit;
    stc_clock_pll_init_t stcPLLHInit;

    /* PCLK0, HCLK  Max 240MHz */
    /* PCLK1, PCLK4 Max 120MHz */
    /* PCLK2, PCLK3 Max 60MHz  */
    /* EX BUS Max 120MHz */
    CLK_SetClockDiv(CLK_BUS_CLK_ALL, \
                    (CLK_PCLK0_DIV1 | CLK_PCLK1_DIV2 | CLK_PCLK2_DIV4 | \
                     CLK_PCLK3_DIV4 | CLK_PCLK4_DIV2 | CLK_EXCLK_DIV2 | \
                     CLK_HCLK_DIV1));

    (void)CLK_XtalStructInit(&stcXtalInit);
    /* Config Xtal and enable Xtal */
    stcXtalInit.u8Mode   = CLK_XTAL_MD_OSC;
    stcXtalInit.u8Drv    = CLK_XTAL_DRV_HIGH;
    stcXtalInit.u8State  = CLK_XTAL_ON;
    stcXtalInit.u8StableTime = CLK_XTAL_STB_2MS;
    (void)CLK_XtalInit(&stcXtalInit);

    (void)CLK_PLLStructInit(&stcPLLHInit);
    /* VCO = (24/3)*120 = 960MHz*/
    stcPLLHInit.u8PLLState = CLK_PLL_ON;
    stcPLLHInit.PLLCFGR = 0UL;
    stcPLLHInit.PLLCFGR_f.PLLM = 3UL - 1UL;
    stcPLLHInit.PLLCFGR_f.PLLN = 120UL - 1UL;
    stcPLLHInit.PLLCFGR_f.PLLP = 4UL - 1UL;
    stcPLLHInit.PLLCFGR_f.PLLQ = 4UL - 1UL;
    stcPLLHInit.PLLCFGR_f.PLLR = 4UL - 1UL;
    stcPLLHInit.PLLCFGR_f.PLLSRC = CLK_PLL_SRC_XTAL;
    (void)CLK_PLLInit(&stcPLLHInit);

    /* Highspeed SRAM set to 0 Read/Write wait cycle */
    SRAM_SetWaitCycle(SRAM_SRAMH, SRAM_WAIT_CYCLE0, SRAM_WAIT_CYCLE0);

    /* SRAM1_2_3_4_backup set to 1 Read/Write wait cycle */
    SRAM_SetWaitCycle((SRAM_SRAM123 | SRAM_SRAM4 | SRAM_SRAMB), SRAM_WAIT_CYCLE1, SRAM_WAIT_CYCLE1);

    /* 0-wait @ 40MHz */
    (void)EFM_SetWaitCycle(EFM_WAIT_CYCLE5);
    (void)EFM_ICacheCmd(ENABLE);
    (void)EFM_DCacheCmd(ENABLE);
    (void)EFM_PrefetchCmd(ENABLE);

    /* 4 cycles for 200 ~ 250MHz */
    GPIO_SetReadWaitCycle(GPIO_RD_WAIT4);

    CLK_SetSysClockSrc(CLK_SYSCLK_SRC_PLL);
}

/** Peripheral Clock Configuration
*/
static void PeripheralClock_Config(void)
{
#if defined(HC32F4A0)
#if defined(BSP_USING_CAN1)
    CLK_SetCANClockSrc(CLK_CAN1, CLK_CANCLK_SYSCLK_DIV6);
#endif
#if   defined(BSP_USING_CAN2)
    CLK_SetCANClockSrc(CLK_CAN2, CLK_CANCLK_SYSCLK_DIV6);
#endif

#if defined(RT_USING_ADC)
    CLK_SetPeriClockSrc(CLK_PERIPHCLK_PCLK);
#endif
#endif
}

/*******************************************************************************
 * Function Name  : SysTick_Configuration
 * Description    : Configures the SysTick for OS tick.
 * Input          : None
 * Output         : None
 * Return         : None
 *******************************************************************************/
void  SysTick_Configuration(void)
{
    stc_clock_freq_t stcClkFreq;
    rt_uint32_t cnts;

    CLK_GetClockFreq(&stcClkFreq);

    cnts = (rt_uint32_t)stcClkFreq.u32HclkFreq / RT_TICK_PER_SECOND;

    SysTick_Config(cnts);
}

/**
 * This is the timer interrupt service routine.
 *
 */
void SysTick_Handler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    rt_tick_increase();

    /* leave interrupt */
    rt_interrupt_leave();
}

/**
 * This function will initial HC32 board.
 */
void rt_hw_board_init()
{
    /* Peripheral registers write unprotected */
    LL_PERIPH_WE(EXAMPLE_PERIPH_WE);

    // 
    GPIO_SetDebugPort(GPIO_PSPCR_SPFE_2 | GPIO_PSPCR_SPFE_3 | GPIO_PSPCR_SPFE_4, DISABLE);

    SystemClock_Config();
    PeripheralClock_Config();
    /* Configure the SysTick */
    SysTick_Configuration();

    /* Heap initialization */
#if defined(RT_USING_HEAP)
    rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
#endif

    /* Board underlying hardware initialization */
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif

#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
    rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
}

void rt_hw_us_delay(rt_uint32_t us)
{
    uint32_t delta = 0;
    uint32_t start, now, reload, us_tick;
    start = SysTick->VAL;
    reload = SysTick->LOAD;
    us_tick = SystemCoreClock / 1000000UL;

    do
    {
        now = SysTick->VAL;
        delta += start > now ?  start - now : reload + start - now;
    }
    while (delta < us_tick * us);
}

#if defined(BSP_USING_SPI)
#define SH_CS_Pin GPIO_PIN_04
#define SH_CS_GPIO_Port GPIO_PORT_A
#define QM8_CS_Pin GPIO_PIN_04
#define QM8_CS_GPIO_Port GPIO_PORT_E
#define SPL06_CS_Pin GPIO_PIN_02
#define SPL06_CS_GPIO_Port GPIO_PORT_B
#if 0
#define BMI2_CS_Pin GPIO_PIN_12
#define BMI2_CS_GPIO_Port GPIO_PORT_E
#endif
#define QMI_CS_Pin GPIO_PIN_15
#define QMI_CS_GPIO_Port GPIO_PORT_E
#define FLASH_CS_Pin GPIO_PIN_02
#define FLASH_CS_GPIO_Port GPIO_PORT_E
#define SDCARD_CS_Pin GPIO_PIN_03
#define SDCARD_CS_GPIO_Port GPIO_PORT_E

int reorotorv1_spi_init(void)
{
    /* rt name max is 8 (RT_NAME_MAX   8) */
    rt_hw_spi_device_attach("spi1", "spi1_d1", SH_CS_GPIO_Port, SH_CS_Pin);

    /* rt name max is 8 (RT_NAME_MAX   8) */
    rt_hw_spi_device_attach("spi1", "spi1_d2", QM8_CS_GPIO_Port, QM8_CS_Pin);

#if 0
    /* rt name max is 8 (RT_NAME_MAX   8) */
    rt_hw_spi_device_attach("spi1", "spi1_d3", BMI2_CS_GPIO_Port, BMI2_CS_Pin);
#endif

    /* rt name max is 8 (RT_NAME_MAX   8) */
    rt_hw_spi_device_attach("spi1", "spi1_d5", SPL06_CS_GPIO_Port, SPL06_CS_Pin);

    /* rt name max is 8 (RT_NAME_MAX   8) */
    rt_hw_spi_device_attach("spi3", "spi3_d1", FLASH_CS_GPIO_Port, FLASH_CS_Pin);

    /* rt name max is 8 (RT_NAME_MAX   8) */
    rt_hw_spi_device_attach("spi3", "spi3_d2", SDCARD_CS_GPIO_Port, SDCARD_CS_Pin);

    return 1;
}
INIT_DEVICE_EXPORT(reorotorv1_spi_init);


#ifdef RT_USING_SPI_MSD
extern rt_err_t msd_init(const char *sd_device_name, const char *spi_device_name);

static int reorotorv1_mnt_init(void)
{
    // sd spi初始配置时钟400K，配置完成后按照SD卡速度设置时钟
    // spi总线速度太快，在spi DMA下会有问题
    // 如，在控制台使用ls命令，无法读取sd卡里的内容
    msd_init("sd0", "spi3_d2");

    return 0;
}
INIT_COMPONENT_EXPORT(reorotorv1_mnt_init);
#endif

#endif

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static int HC_GPIO_Init(void)
{
    stc_gpio_init_t stcGpioInit;

    GPIO_StructInit(&stcGpioInit);
    stcGpioInit.u16PinState = PIN_STAT_SET;
    stcGpioInit.u16PinDir   = PIN_DIR_OUT;
    stcGpioInit.u16PullUp   = PIN_PU_ON;
    GPIO_Init(SH_CS_GPIO_Port, SH_CS_Pin, &stcGpioInit);

    GPIO_StructInit(&stcGpioInit);
    stcGpioInit.u16PinState = PIN_STAT_SET;
    stcGpioInit.u16PinDir   = PIN_DIR_OUT;
    stcGpioInit.u16PullUp   = PIN_PU_ON;
    GPIO_Init(QM8_CS_GPIO_Port, QM8_CS_Pin, &stcGpioInit);

    GPIO_StructInit(&stcGpioInit);
    stcGpioInit.u16PinState = PIN_STAT_SET;
    stcGpioInit.u16PinDir   = PIN_DIR_OUT;
    stcGpioInit.u16PullUp   = PIN_PU_ON;
    GPIO_Init(SPL06_CS_GPIO_Port, SPL06_CS_Pin, &stcGpioInit);

#if 0
    GPIO_StructInit(&stcGpioInit);
    stcGpioInit.u16PinState = PIN_STAT_SET;
    stcGpioInit.u16PinDir   = PIN_DIR_OUT;
    stcGpioInit.u16PullUp   = PIN_PU_ON;
    GPIO_Init(BMI2_CS_GPIO_Port, BMI2_CS_Pin, &stcGpioInit);
#endif

    GPIO_StructInit(&stcGpioInit);
    stcGpioInit.u16PinState = PIN_STAT_SET;
    stcGpioInit.u16PinDir   = PIN_DIR_OUT;
    stcGpioInit.u16PullUp   = PIN_PU_ON;
    GPIO_Init(QMI_CS_GPIO_Port, QMI_CS_Pin, &stcGpioInit);

    GPIO_StructInit(&stcGpioInit);
    stcGpioInit.u16PinState = PIN_STAT_SET;
    stcGpioInit.u16PinDir   = PIN_DIR_OUT;
    stcGpioInit.u16PullUp   = PIN_PU_ON;
    GPIO_Init(FLASH_CS_GPIO_Port, FLASH_CS_Pin, &stcGpioInit);

    GPIO_StructInit(&stcGpioInit);
    stcGpioInit.u16PinState = PIN_STAT_SET;
    stcGpioInit.u16PinDir   = PIN_DIR_OUT;
    stcGpioInit.u16PullUp   = PIN_PU_ON;
    GPIO_Init(SDCARD_CS_GPIO_Port, SDCARD_CS_Pin, &stcGpioInit);

    return 0;
}
INIT_BOARD_EXPORT(HC_GPIO_Init);

/*********************************test************************************************/
